Godotのawait入門
Godotについて
GodotはMITライセンスで開発されているゲームエンジンです。
複数プラットフォームに対応したゲームエンジンで、PCだけでなくスマートフォンやWeb向けにもビルド可能です。
2014年から開発が開始されており、割と成熟したエンジンではありますが日々改善が施されています。
バージョン
今回使用しているのはGodot Engine v4.1.3
です。
GDScriptのawaitについて
GDScriptのawaitはシグナルの待機やコルーチンを作りたい時に便利です。
以下のような形式で書きます。
await {SINGAL}
このように書くとシグナルが発行されるまで残りの処理を待機します。 例えば以下のようなケースで便利です。
await {サーバーとの通信完了シグナル} await {アニメーション処理の完了シグナル}
この例では、サーバーとの通信完了を待ってアニメーションを実行したいのですが、素朴にsignalのconnectを使って書くと少し大変です。 非同期的な処理をあたかも同期的に書きたいシーンで便利だと思います。
もう少し複雑な例
以下は5秒間待ってからLabelノードのテキストを変更するような例です。 少し複雑にして、クラス内部で定義されたシグナルも使っています。
extends Label signal text_updated(counter: int) var timeout_counter := 0 func _rewrite_label(timer: SceneTreeTimer): print("Wait timer timeout") await timer.timeout print("Timeout") text = "Time Out" print("Text updated") timeout_counter += 1 text_updated.emit(timeout_counter) print("Fin _rewrite_label") func _on_text_updated(): print("Wait singal: text_updated") var counter = await text_updated print("Catch signal: text_updated") print("Current counter: {counter}".format({"counter": counter})) # Called when the node enters the scene tree for the first time. func _ready(): text = "Start" print("Timer start") var timer = get_tree().create_timer(5) print("Call async func") _rewrite_label(timer) _on_text_updated() print("Ready")
実行すると以下のようなコンソールの出力が得られます。
Timer start Call async func Wait timer timeout Wait singal: text_updated Ready Timeout Text updated Catch signal: text_updated Current counter: 1 Fin _rewrite_label
処理の流れを整理すると以下のような感じになります。
ポイントとしてはreturn
またはawait
のタイミングで非同期関数を呼び出した場所に帰ってくるということです。
注意点としてはシグナルを発行するとそれを待機しているところに処理が移るということです。
func _rewrite_label(timer: SceneTreeTimer): # ... text_updated.emit(timeout_counter) # <-シグナルの発行後、待機していた_on_text_updatedの処理が再開される print("Fin _rewrite_label") # <-ここは_on_text_updatedの処理が完了した時に実行される
最後に
awaitを使うことでシンプルにコードを書けるケースもあると思います。 ただ、シグナルのconnectメソッドを使った方が簡単に書けるケースもあると思うので使い分けは難しいです...
個人的はいくつものシグナルの実行順を制御したい場合はawaitを使っています。